package Waya::Node;

use warnings;
use strict;
use Waya::Constants ':traverse';

use base 'Waya::Base';

__PACKAGE__->mk_hash_accessors(qw(notes));


sub move    { $_[0]->{B} || $_[0]->{W} }
sub comment { $_[0]->{C} }


sub is_leaf {
    my $self = shift;
    !defined $self->{next};
}


sub is_game_info_node {
    my $self = shift;
    $self->{_is_game_info_node};
}


sub does_variation_follow {
    my $self = shift;
    !$self->is_leaf && (ref $self->{next} eq 'Waya::Variation');
}


sub as_sgf {
    my $self = shift;
    my $sgf = ';';
    while (my ($key, $value) = each %$self) {
        next unless $key =~ /^[A-Z]{1,2}$/;
        $sgf .= $key;
        $sgf .= "[$_]" for ref $value eq 'ARRAY' ? @$value : $value;
    }

    unless ($self->is_leaf) {
        no warnings 'recursion';
        $sgf .= $self->{next}->as_sgf;
    }

    $sgf;
}


sub traverse_node {
    my ($self, $code) = @_;
    my $rc = $code->($self) || 0;
    return $rc if $rc == RC_PRUNE;

    if ($rc == RC_DELETE) {
        $self->{next} = undef;
        return $rc;
    }

    unless ($self->is_leaf) {
        no warnings 'recursion';
        $self->{next}->traverse_node($code);
    }
    return RC_CONTINUE;
}


sub traverse_coord {
    my ($self, $code) = @_;

    my $prune = 0;

    # if a callback indicates (via RC_PRUNE) that we should prune the
    # traversal here, we'll still process all the properties in this node,
    # then prune.

    for my $key (qw/B W AB AW AE MA CR SQ TR VW TB TW/) {
        next unless $self->{$key};
        for (ref $self->{$key} eq 'ARRAY' ? @{ $self->{$key} } : $self->{$key}) {
            my $rc = $code->($_);
            $prune++ if ($rc || 0) == RC_PRUNE;
        }
    }

    if ($self->{LB}) {
        for (ref $self->{LB} eq 'ARRAY' ?  @{ $self->{LB} } : $self->{LB}) {
            my $rc = $code->($_->coord);
            $prune++ if ($rc || 0) == RC_PRUNE;
        }
    }

    return RC_PRUNE if $prune;
    unless ($self->is_leaf) {
        no warnings 'recursion';
        $self->{next}->traverse_coord($code);
    }
    return RC_CONTINUE;
}


sub strip_variations {
    my $self = shift;

    return if $self->is_leaf;

    # If there is a variation node after this one, only link to the first
    # variation and forget the rest (including the variation node, of course).
    # Because of the way the nodes are sewn up, they'll still be there in the
    # list of nodes, just not linked. They're dark nodes.

    if ($self->does_variation_follow) {
        $self->{next} = $self->{next}[0][0];
    }
    no warnings 'recursion';
    $self->{next}->strip_variations;
}


1;
